﻿// -----------------------------------------------------------------------
// <copyright file="BinaryReaderEx.cs" company="none">
// Copyright (c) 2012 M. Alberti, xanatos(at)live.it
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
// </copyright>
// -----------------------------------------------------------------------

namespace FluentSerializer.Utilities
{
    using System;
    using System.IO;

    /// <summary>
    /// 
    /// </summary>
    public static class BinaryReaderEx
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="reader"></param>
        /// <returns></returns>
        public static IntPtr ReadIntPtr(this BinaryReader reader)
        {
            if (IntPtr.Size == sizeof(int))
            {
                return new PrimitiveTypeConverter { UInt32A = reader.ReadUInt32() }.IntPtr;
            }

            return new PrimitiveTypeConverter { UInt64 = reader.ReadUInt64() }.IntPtr;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="reader"></param>
        /// <returns></returns>
        public static UIntPtr ReadUIntPtr(this BinaryReader reader)
        {
            if (UIntPtr.Size == sizeof(uint))
            {
                return new PrimitiveTypeConverter { UInt32A = reader.ReadUInt32() }.UIntPtr;
            }

            return new PrimitiveTypeConverter { UInt64 = reader.ReadUInt64() }.UIntPtr;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="reader"></param>
        /// <param name="buffer"></param>
        /// <param name="offset"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public static int ReadFixed(this BinaryReader reader, byte[] buffer, int offset, int count)
        {
            return reader.Read(buffer, sizeof(byte), offset, count);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="reader"></param>
        /// <param name="buffer"></param>
        /// <param name="offset"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public static int ReadFixed(this BinaryReader reader, char[] buffer, int offset, int count)
        {
            return reader.Read(buffer, sizeof(char), offset, count);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="reader"></param>
        /// <param name="buffer"></param>
        /// <param name="offset"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public static int Read(this BinaryReader reader, bool[] buffer, int offset, int count)
        {
            return reader.Read(buffer, sizeof(bool), offset, count);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="reader"></param>
        /// <param name="buffer"></param>
        /// <param name="offset"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public static int Read(this BinaryReader reader, short[] buffer, int offset, int count)
        {
            return reader.Read(buffer, sizeof(short), offset, count);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="reader"></param>
        /// <param name="buffer"></param>
        /// <param name="offset"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public static int Read(this BinaryReader reader, ushort[] buffer, int offset, int count)
        {
            return reader.Read(buffer, sizeof(ushort), offset, count);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="reader"></param>
        /// <param name="buffer"></param>
        /// <param name="offset"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public static int Read(this BinaryReader reader, int[] buffer, int offset, int count)
        {
            return reader.Read(buffer, sizeof(int), offset, count);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="reader"></param>
        /// <param name="buffer"></param>
        /// <param name="offset"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public static int Read(this BinaryReader reader, uint[] buffer, int offset, int count)
        {
            return reader.Read(buffer, sizeof(uint), offset, count);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="reader"></param>
        /// <param name="buffer"></param>
        /// <param name="offset"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public static int Read(this BinaryReader reader, long[] buffer, int offset, int count)
        {
            return reader.Read(buffer, sizeof(long), offset, count);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="reader"></param>
        /// <param name="buffer"></param>
        /// <param name="offset"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public static int Read(this BinaryReader reader, ulong[] buffer, int offset, int count)
        {
            return reader.Read(buffer, sizeof(ulong), offset, count);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="reader"></param>
        /// <param name="buffer"></param>
        /// <param name="offset"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public static int Read(this BinaryReader reader, float[] buffer, int offset, int count)
        {
            return reader.Read(buffer, sizeof(float), offset, count);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="reader"></param>
        /// <param name="buffer"></param>
        /// <param name="offset"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public static int Read(this BinaryReader reader, double[] buffer, int offset, int count)
        {
            return reader.Read(buffer, sizeof(double), offset, count);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="reader"></param>
        /// <param name="buffer"></param>
        /// <param name="offset"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public static int Read(this BinaryReader reader, IntPtr[] buffer, int offset, int count)
        {
            return reader.Read(buffer, IntPtr.Size, offset, count);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="reader"></param>
        /// <param name="buffer"></param>
        /// <param name="offset"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public static int Read(this BinaryReader reader, UIntPtr[] buffer, int offset, int count)
        {
            return reader.Read(buffer, UIntPtr.Size, offset, count);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="reader"></param>
        /// <param name="buffer"></param>
        /// <param name="sizeElement"></param>
        /// <param name="offset"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public static int Read(this BinaryReader reader, Array buffer, int sizeElement, int offset, int count)
        {
            int count2;

            if (sizeElement == 1 && buffer is byte[])
            {
                count2 = reader.Read((byte[])buffer, offset, count);

                if (count != count2)
                {
                    throw new EndOfStreamException();
                }

                return count2;
            }

            offset *= sizeElement;
            count *= sizeElement;

            var buffer2 = new byte[count];
            count2 = reader.Read(buffer2, 0, buffer2.Length);
            System.Buffer.BlockCopy(buffer2, offset, buffer, 0, count2);

            if (count != count2)
            {
                throw new EndOfStreamException();
            }

            return count;
        }
    }
}